/* 
	LMtmr_Set_Timer 				1 unit = 625us
	rdabt_timer_create		  		1 unit = 100ms
	
	Notice: tports, watch clock (0x40200000,0x44210aaa);
	
	
*/

#include "sys_config.h"
#include "sys_types.h"

#include "bt_types.h"
#include "host_config.h"
#include "papi.h"
#include "hid.h"
#include "hid_wii.h"
#include "hid_main.h"
#include "hs_battery.h"
#include "hw_i2c_driver.h"
#include "hw_delay.h"
#include "lmp_scan.h"
#include "hid_core.h"
#include "tra_combined.h"
#include "lmp_utils.h"
#include "lmp_timer.h"
#include "Manager.h"
#include "mgr_link.h"
#include "hw_apb_spi.h"
#include "patch.h"
#include "lmp_link_key_db.h"
#include "sdp_db.h"
#include "spp_dun.h"
#include "sys_rda_arm.h"


#define SPP_SNIFF_INTERVAL 		0x320

#define SPP_SEND_TIME			24  // 16:10ms  24:15ms

#define LED_ON  			   LED_ALWAYS_DARK//LED_ALWAYS_LIGHT
#define LED_OFF				   LED_ALWAYS_LIGHT//LED_ALWAYS_DARK



#define LED_Power              1
#define LED_Pair               0
#define WP_IIC_PIN             2
#define NOUSE				   				 3
#define LED_CHARGE       NOUSE
#define LED_CAPS			   NOUSE


/* for hid_config_eeprom */
#define HID_DEBUG_UART                      0x01
#define HID_DEBUG_CUSTOMER					0x02
#define HID_DEBUG_SLEEP					    0x04
#define HID_DEBUG_LOW_POWER					0x08
#define HID_DEBUG_SNIFF_3					0x10
//#define HID_DEBUG_SPP						0x20
#define HID_TEST_SPP						0x20


extern u_int8   gLinkIndex;
extern u_int8   hFifoIndex;
extern u_int8   ghid_fifo[24];
extern u_int8  reportFlag;
extern t_hid_pskey  hid_config_eeprom;
extern HID   ghid;
extern u_int8 hid_led_num[4];
extern u_int16     gHidHandle;
extern t_lmp_link *hid_link;
extern t_SYS_Config g_sys_config;

extern u_int32 sdp_replace_data[8];
extern const t_SDP_serviceRecord sdp_spp_service;
extern t_FHSpacket LC_local_device_fhs;
extern u_int8 isSaveKey;



extern void HSMain_InitSleepMode(void *dummy);


extern u_int8 LMtmr_Set_Timer(t_slots timer_value,void ((*p_funct)(t_lmp_link*)), t_lmp_link* p_link, u_int8 dynamic);
extern void _HID_INT_Disable(void);
extern  u_int8 LMkeydb_EEprom_Load_Addr_link_Key(u_int16 baseAddr);
extern  void HID_Init_Keyboard(void);
extern void _HID_INT_Enable(void);
extern void _Set_PWM_Ratio(u_int8  mode,u_int16 initial,u_int16 toggle);

u_int8  p_sppRxFlag;
u_int8  sppTimer;
volatile   u_int32 keycon;
u_int8  spp_t[32];



// Notice: Word Alignment
const u_int8 hid_bd_addr[8] = {0xbb, 0x99, 0x77, 0x55, 0x33, 0x11,0x00,0x00}; // spp addr

//browse list
const t_SDP_dataElement attribute_spp_browse[]= 
{
    0x0001, 0x0003, 0x0002, (u_int8*)0x00001002,
};

const u_int8 spp_service_name[] = "Test SPP Slave";


const t_SDP_dataElement p_spp_service_class[]=
{
    0x0001, 0x0003, 0x0002, (u_int8*)0x00001101  //spp
};

const t_SDP_dataElement p_spp_pdl_l2cap[]= 
{
    0x0001, 0x0003, 0x0002, (u_int8*)0x00000100
};

const t_SDP_dataElement p_spp_pdl_rfcomm[]= 
{
    0x0001, 0x0003, 0x0002, (u_int8*)0x00000003, //rfcomm
    0x0000, 0x0001, 0x0001, (u_int8*)0xfffffff1, //channel number: 7   
};


const t_SDP_dataElement p_spp_pdl[]= 
{
    0x0005, 0x0006, 0x0003, (u_int8*)p_spp_pdl_l2cap,
    0x0005, 0x0006, 0x0005, (u_int8*)p_spp_pdl_rfcomm    
};


const t_SDP_dataElement p_spp_profile_list[]= 
{
    0x0001, 0x0003, 0x0002, (u_int8*)0x00001101,  //profile spp
    0x0001, 0x0001, 0x0002, (u_int8*)0x00000100   //profile version
};
const t_SDP_dataElement p_spp_profile[]= 
{
    0x0005, 0x0006, 0x0006, (u_int8*)p_spp_profile_list
};



//    id          size,      type     length          data
const t_SDP_attribute p_attribute_spp[] = 
{
    {0x0000, 0x0002, 0x0001, 0x0004, (u_int8*)0x00010007},                                            //SDP_AID_RECORD_HANDLE
    {0x0001, 0x0005, 0x0006, 0x0003, (u_int8*)p_spp_service_class},                //SDP_AID_SERVICE_CLASS
    {0x0004, 0x0005, 0x0006, 0x000c, (u_int8*)p_spp_pdl},                                 //SDP_AID_PROTOCOL
    {0x0005, 0x0005, 0x0006, 0x0003, (u_int8*)attribute_spp_browse},                                 //SDP_AID_BROWSE_LIST
    {0x0009, 0x0005, 0x0006, 0x0008, (u_int8*)p_spp_profile},                         //SDP_AID_PROFILE_LIST
    {0x0100, 0x0005, 0x0004, 0x0016, (u_int8*)spp_service_name},  
};

const t_SDP_serviceRecord p_spp_service =
    {sizeof(p_attribute_spp)/sizeof(p_attribute_spp[0]), p_attribute_spp};



void  p_spp_set_PWM(u_int8 onOff,u_int16  initial, u_int16  toggle)               
{
	u_int32 tmp;
	u_int32 value;

	
	
	if(onOff == 0){
		// disable PWM
		tmp = HID_READ_REG_UINT32(0x70);
		tmp &= ~(1<<5);
		HID_WRITE_REG_UINT32(0x70,tmp);
		return;

	}

	 	
		
	// enable PWM
	tmp = HID_READ_REG_UINT32(0x70);
	tmp |= 1<<5;
	HID_WRITE_REG_UINT32(0x70,tmp);

	value = HID_READ_REG_UINT32(0x30);		
	value |= 0x01<<3;
	HID_WRITE_REG_UINT32(0x30,value);
		

    if(toggle == 0x00){
		tmp = HID_READ_REG_UINT32(0x08);
		tmp &= ~(1<<15);
		HID_WRITE_REG_UINT32(0x08,tmp);
		return;
    }
	else{	
		// set value
		tmp = HID_READ_REG_UINT32(0x08);
		tmp |= 0x8000;
		HID_WRITE_REG_UINT32(0x08,tmp);
	}
	

	_Set_PWM_Ratio(LED_MOTOR,initial,toggle);
}


u_int32 gcount;

void p_send_spp_data(t_lmp_link* p_link)
{
	LMtmr_Reset_Timer(sppTimer,SPP_SEND_TIME);
	
	if(ghid.state == HidConnected){
		gcount++;
		ghid_fifo[3] = gcount & 0xff;
		ghid_fifo[2] = gcount>>8 & 0xff;
		ghid_fifo[1] = gcount>>16 & 0xff;
		ghid_fifo[0] = gcount>>24 & 0xff;

		
		if(gcount==0xffffffff)
			gcount = 0;
		
		SPP_Send_Data(ghid_fifo, 8, 0);

	}
	
}


/* The fuction replaces 'inline' FHS_Set_Device_Class for patch compile*/
void p_Set_Device_Class(t_FHSpacket *fhs, t_classDevice class_of_device)
{
    u_int8 *p_fhs_device_class = fhs->payload+11;
    *p_fhs_device_class++ = (u_int8) (class_of_device & 0xFF);
    class_of_device >>=8;
    *p_fhs_device_class++ = (u_int8) (class_of_device & 0xFF);
    class_of_device >>=8;
    *p_fhs_device_class++ = (u_int8) (class_of_device & 0xFF);
}


void p_spp_init()
{
	u_int8  tmp,i;
	u_int32 value;
	u_int16 value16;
	

	for(i=0;i<4;i++)
		hid_led_num[i] = NOUSE;
    
	
	// Set local bd_addr
	//SYShalconfig_Get_Stored_BD_ADDR(hid_bd_addr);
	// Set local name	
	LMconfig_LM_Change_Local_Name((u_int8 *)"Test SPP");   
	hid_config_eeprom.ioCapability = MGR_IOCAP_DISPLAY_YESNO; //MGR_IOCAP_DISPLAY_YESNO;
	ghid.pinCodeStatus = HID_PINCODE_IDLE;
	MGR_SetSecurityMode(MGR_NOSECURITY);
	// Set COD
	g_sys_config.device_class = 0x200404;  // laptop:0x02010c, headset:0x200404
	p_Set_Device_Class(&LC_local_device_fhs, g_sys_config.device_class);

	// SSP
	//g_sys_config.feature_set[6] = 0x59;    //0xf7 specified for ssp  (close SSP)
	//g_sys_config.feature_set[7] = 0x87;   // 0x7b specified for ipad

	// Pin_code
	g_sys_config.feature_set[6] = 0x51;
	g_sys_config.feature_set[7] = 0x00;

	rdabt_sdp_replace_service(0x10000, NULL); // remove hfp sdp record
    rdabt_sdp_replace_service(0x10001, NULL); // remove hs sdp record
    rdabt_sdp_replace_service(0x1000a, NULL); // remove hid sdp record
    rdabt_sdp_replace_service(0x10007, &p_spp_service); // restore spp sdp record

	
	
    sdp_replace_data[1] = 1; // service port number
	SPP_Active_Req(1);     // start listening on the port

	// Init the register set
	_HID_INT_Disable();
	
				   
	HID_WRITE_REG(0x40,0x00);
	HID_WRITE_REG_UINT32(0x04,0xCF7CFFFF);		// enable the wii key
	   

	HID_WRITE_REG_UINT32(0x10,0x4000);			// enable the p1_6 input
						

	//HID_WRITE_REG(0x70,0x1f);	 // key mode  bit6 :  1 :key pull_up mode and 0 : key pull down.
	// pull up the GPIO
	HID_WRITE_REG_UINT32(0x14,0x00000000);	// uart rx
	//pull down the ext_int
	HID_WRITE_REG_UINT32(0x18,0x4fff);

	HID_WRITE_REG_UINT32(0x30,0x800000);  	// clk_sel = fast  
	HID_WRITE_REG(0xe8,0xf); // Pwm_led_en		
	HID_WRITE_REG_UINT32(0x08,0x0f008000);	// PWM output


	// set AGPIO +26M (mux GPIO)
	//Bit[25:21]	Analog/Digital sel	WR/WW	0: Analog 1:digital   bit21: 26M
	value = HID_READ_REG_UINT32(0x20);
	value &= ~(0x1<<21);
	HID_WRITE_REG_UINT32(0x20,value);

	//enable GPIO INT
	//HID_WRITE_REG_UINT32(0x1c,0x48000000);	

	// Set 5408 interface by SPI 0x13*4+0x200 
   // set P0_5 P0_6 to input     
   value16 = HW_SPI_Read_Data(0x24c);
   value16 &= ~0xff;  
   value16 |= 0x24;
   HW_SPI_Write_Data(0x24c,value16);
	
	
	 _HID_INT_Enable();
	 HID_WRITE_REG(0x40,0x0a);

	// slow flash
	HID_WRITE_REG_UINT32(0xf0,0xfa00);
	HID_WRITE_REG_UINT32(0xf8,0xfcff);
	//quick flash
	HID_WRITE_REG_UINT32(0xf4,0xfe00);
	HID_WRITE_REG_UINT32(0xfc,0xff00);


	for(i=0;i<4;i++)
	HID_Set_LED(i,LED_OFF,0x7fff); 

   	HID_Set_LED(2,LED_ON,0x7fff); 
	HID_Set_LED(1,LED_FLASH,0x7fff); 


	//p_spp_set_PWM(1,0xff7f,0xffb2);
	p_spp_set_PWM(1,hid_config_eeprom.lowPowerInit,hid_config_eeprom.lowPowerToggle);

	



	// the page size of C42A & C64A is 32-byte.
	hid_config_eeprom.linkeyAddr = 0x1fc0;
	gLinkIndex = LMkeydb_EE_Load_Link();	

	//pin code
	 
	//  g_sys_config.feature_set[6] = 0x51;    
	//  g_sys_config.feature_set[7] = 0x00;   

		

	
	LMscan_Write_Scan_Enable(BOTH_SCANS_ENABLED);
	
	HSBattery_Initialise();  // Notice: impact on the scan
	RDA_WRITE_REG_BYTE(RDA_APB_PMU_BASE+0x10c,0x30);  // disable HW control LED
	RDA_WRITE_REG_BYTE(RDA_APB_PMU_BASE+0x10b,RDA_READ_REG_BYTE(RDA_APB_PMU_BASE+0x10b)&0xfe);  // Disable the Shutdown of Charge
	RDA_WRITE_REG_BYTE(RDA_APB_PMU_BASE+0x1a7,1); // 26M stablize time : 1ms
	
	if(hid_config_eeprom.testDebug & HID_DEBUG_SLEEP){
		
		rdabt_timer_create(30, HSMain_InitSleepMode, NULL, RDABT_TIMER_ONESHOT);  // 3 secs
	}

	if(hid_config_eeprom.testDebug & HID_TEST_SPP){

		sppTimer = LMtmr_Set_Timer(SPP_SEND_TIME,p_send_spp_data,NULL,0);
	}


}




void p_spp_disconnect(u_int8 result)
{
	ghid.state = HidIdle;
	ghid.pinCodeStatus = HID_PINCODE_IDLE;
	
	spp_t[0] = 0x22;
	spp_t[1] = result;
	HID_Send_UART(spp_t,2);
}


void p_spp_rx_data(u_int8 *ptr, u_int8 length)
{
	if(hid_config_eeprom.testDebug & HID_DEBUG_UART)
		HID_Send_UART(ptr,length);
	
	
	if(ptr[0] == 0xaa){
		
		sppTimer = LMtmr_Set_Timer(SPP_SEND_TIME,p_send_spp_data,NULL,0);
	}
	else if(ptr[0] == 0xbb){
		LMtmr_Clear_Timer(sppTimer);
		sppTimer = 0;
		gcount = 0;
		
	}
		
}

void p_spp_lm_connected(u_int8 result,u_int16 handle)
{
	
	gLinkIndex = 0x00;
	ghid.state = HidConnected;   // don't forget the state for  rdabt_update_sniff_timer()
	
	// Notice: Can't save the addr in the lm_connected phase
	//LMkeydb_EE_Save_Addr();

	// Disable the EEPROM write-protect

	if(hid_config_eeprom.testDebug & HID_DEBUG_SLEEP){
		hid_link->min_interval = 0; 
	hid_link->max_interval = 0x0320;
	hid_link->adjust_interval = 20;
	
	hid_link->sniffTimer = rdabt_timer_create(hid_link->adjust_interval, rdabt_link_sniff_timeout, (void *)hid_link, RDABT_TIMER_PERIODIC);
		
	}
}





void p_spp_isr(void)
{	
	//keycon = HID_READ_REG(KEYBOARD_STATUS_OFFSET); 
	keycon=HID_READ_REG_UINT32(0x3c);  // clear the  int

	if(hid_config_eeprom.testDebug & HID_DEBUG_UART){
		ghid_fifo[0] = keycon & 0xff;
		ghid_fifo[1] = keycon>>8 & 0xff;
		ghid_fifo[2] = keycon>>16 & 0xff;
		ghid_fifo[3] = keycon>>24 & 0xff;
		
		HID_Send_UART(ghid_fifo,4); 
		
		return;
	}
	
}




void p_spp_sch()
{
	// Enable the EEPROM write-protect
	if(isSaveKey == 1){
		
	}
}










#if 0
void p_spp_isr()
{	
	keycon=HID_READ_REG_UINT32(0x3c);  // clear the  int

	
	
}


void p_spp_sch()
{

}


void p_spp_rx_ack(u_int16 handle)
{
	spp_t[0] = 0x33;
	spp_t[1] = handle & 0xff;
	spp_t[2] = handle>>8 & 0xff;
	HID_Send_UART(spp_t,3);
	
}


void p_spp_link_sniff_timeout(void *arg)
{
    t_lmp_link* dbEntry = (t_lmp_link*)arg;

	
    if(dbEntry->deviceMode == MGR_DEVACTIVE)
    {
       		
        LMpolicy_LM_Sniff_Mode(dbEntry, SPP_SNIFF_INTERVAL, SPP_SNIFF_INTERVAL, hid_config_eeprom.sniffAttmpt, hid_config_eeprom.sniffTimeout); 
        dbEntry->deviceMode = MGR_DEVPENDINGSNIFF;
    }
    else if(dbEntry->deviceMode == MGR_DEVSNIFF)
    {
    	if(dbEntry->interval>= SPP_SNIFF_INTERVAL){
			rdabt_cancel_timer(dbEntry->sniffTimer);
			dbEntry->sniffTimer = 0;
			return;
    	}
		
        LMpolicy_LM_Exit_Sniff_Mode(dbEntry);
        dbEntry->deviceMode = MGR_DEVPENDINGEXITSNIFF;
        
    }
    else if(dbEntry->deviceMode == MGR_DEVPENDINGACTIVE)
    {
        rdabt_mgr_releaseACL(dbEntry->handle, RDABT_USER_ENDED_CONNECTION);
    }
}


#endif

 
